package Kernel;

import java.io.Serializable;
import java.util.Calendar;

import java.util.GregorianCalendar;

/**
 * Classe Billet comporte le nom et prénom du client et toutes les
 * caractéristiques d'un trajet
 * 
 * @author Dalleau
 * 
 */
// Type modif a gerer
public class Billet implements Serializable {
	private static final long serialVersionUID = 1L;
	private ProfilPassager passager;
	private Client client;
	private Trajet typeTrajet;
	private double prixDeBase;
	private String typeDeBillet;
	private double reduction;
	private boolean premiereClasse;
	private boolean classeAffaire;
	private boolean repas;
	private boolean bonusConfort;
	private boolean carteFidelite;
	private boolean modifier;

	/**
	 * Constructeur par défaut
	 */

	public Billet() {
		this.passager = ProfilPassager.ADULTE;
		this.client = new Client();
		this.typeTrajet = new Trajet();
		this.prixDeBase = typeTrajet.getTarif();
		this.typeDeBillet = typeTrajet.getTypeDeBase();
		this.premiereClasse = false;
		this.classeAffaire = false;
		this.repas = false;
		this.bonusConfort = false;
		this.carteFidelite = false;
		this.modifier = false;
		reduction = 0.0;

	}

	/**
	 * Constructeur Passager
	 * 
	 * @param passager
	 *            la caractéristique du passager,enfant..
	 * @param typeTrajet
	 *            court ou long
	 */
	public Billet(ProfilPassager passager, Client client, Trajet typeTrajet) {
		this.passager = passager;
		this.client = client;
		this.typeTrajet = typeTrajet;
		this.prixDeBase = typeTrajet.getTarif();
		this.typeDeBillet = typeTrajet.getTypeDeBase();
		this.premiereClasse = false;
		this.classeAffaire = false;
		this.repas = false;
		this.bonusConfort = false;
		this.carteFidelite = false;
		this.modifier = false;
		reduction = 0.0;
	}

	// Methode

	/**
	 * Méthode Temps Trajet permet de déterminer la durée d'un trajet
	 * 
	 * @return GregorianCalendar
	 */

	public GregorianCalendar TempsTrajet() {
		boolean memeJour = dateEqual(typeTrajet.getDateArrivee(), (typeTrajet
				.getDateDepart()));
		GregorianCalendar date = (GregorianCalendar) typeTrajet
				.getDateArrivee().clone();
		if (memeJour == false) {
			date.add(Calendar.YEAR, -typeTrajet.getDateDepart().get(
					Calendar.YEAR));
			date.add(Calendar.MONTH, -typeTrajet.getDateDepart().get(
					Calendar.MONTH));
			date.add(Calendar.DATE, -typeTrajet.getDateDepart().get(
					Calendar.DATE));
		}
		date.add(Calendar.HOUR, -typeTrajet.getDateDepart().get(Calendar.HOUR));
		date.add(Calendar.MINUTE, -typeTrajet.getDateDepart().get(
				Calendar.MINUTE));
		return date;
	}

	/**
	 * Méthode Date Equal
	 * 
	 * @param dateA
	 *            GregorianCalendar
	 * @param dateD
	 *            GregorianCalendar
	 * @return return si deux dates sont equals ou non.
	 */
	public boolean dateEqual(GregorianCalendar dateA, GregorianCalendar dateD) {
		GregorianCalendar dateCourante = new GregorianCalendar();
		dateCourante = (GregorianCalendar) dateA.clone();
		dateCourante.clear(Calendar.HOUR);
		dateCourante.clear(Calendar.MINUTE);
		dateCourante.clear(Calendar.SECOND);
		GregorianCalendar dateReference = new GregorianCalendar();
		dateReference = (GregorianCalendar) dateD.clone();
		dateReference.clear(Calendar.HOUR);
		dateReference.clear(Calendar.MINUTE);
		dateReference.clear(Calendar.SECOND);

		// return (dateCourante.before(dateReference) ||
		// dateCourante.equals(dateReference))
		return dateCourante.equals(dateReference);
	}

	/**
	 *Méthode typeReduction permet de faire appel aux méthodes de réduction
	 * selon le type de transport
	 */
	public void typeReduction() {
		if (typeTrajet.getVehicule() instanceof Bus) {
			bonusReductionBus();
		}
		if (typeTrajet.getVehicule() instanceof Train
				|| typeTrajet.getVehicule() instanceof Bateau) {
			bonusReductionTrainBateau();
		}
		if (!(typeTrajet.getVehicule() instanceof Bus)
				&& !(typeTrajet.getVehicule() instanceof Bateau)
				&& !(typeTrajet.getVehicule() instanceof Train)) {
			bonusReductionAvionAutre();
		}

	}

	/**
	 * Méthode de réduction si le transport associé au billet est un bus la
	 * réduction dépend du temps du trajet et du type de passager
	 * 
	 */
	private void bonusReductionBus() {
		GregorianCalendar date = TempsTrajet();
		boolean memeJour = dateEqual(typeTrajet.getDateArrivee(), (typeTrajet
				.getDateDepart()));
		if (memeJour == true && date.get(Calendar.MINUTE) < 55) { // trajet
			// cours
			if (passager == ProfilPassager.ENFANT) {
				reduction = prixDeBase / 2.0;
			} else if (passager == ProfilPassager.JEUNE) {
				reduction = (prixDeBase * 30.0) / 100.0;
			} else if (passager == ProfilPassager.ETUDIANT) {
				reduction = (prixDeBase * 30.0) / 100.0;
			} else if (passager == ProfilPassager.SENIOR) {
				reduction = (prixDeBase * 30.0) / 100.0;
			}
		} else {// Trajet long
			if (passager == ProfilPassager.ENFANT) {
				reduction = (prixDeBase * 20.0) / 100.0;
			} else if (passager == ProfilPassager.JEUNE) {
				reduction = (prixDeBase * 10.0) / 100.0;
			} else if (passager == ProfilPassager.ETUDIANT) {
				reduction = (prixDeBase * 10.0) / 100.0;
			} else if (passager == ProfilPassager.SENIOR) {
				reduction = (prixDeBase * 20.0) / 100.0;
			}
		}
	}

	/**
	 * Méthode de réduction si le transport associé au billet est un train ou un
	 * bateau la réduction dépend du temps du trajet et du type de passager.
	 * 
	 */
	private void bonusReductionTrainBateau() {
		GregorianCalendar date = TempsTrajet();
		boolean memeJour = dateEqual(typeTrajet.getDateArrivee(), (typeTrajet
				.getDateDepart()));
		if (memeJour == true && date.get(Calendar.HOUR) < 2) { // trajet cours
			if (passager == ProfilPassager.ENFANT) {
				reduction = (prixDeBase * 20.0) / 100.0;
			} else if (passager == ProfilPassager.JEUNE) {
				reduction = (prixDeBase * 15.0) / 100.0;
			} else if (passager == ProfilPassager.ETUDIANT) {
				reduction = (prixDeBase * 15.0) / 100.0;
			} else if (passager == ProfilPassager.SENIOR) {
				reduction = (prixDeBase * 20.0) / 100.0;
			}

		} else {// Trajet long
			if (passager == ProfilPassager.ENFANT) {
				reduction = (prixDeBase * 30.0) / 100.0;
			} else if (passager == ProfilPassager.ENFANT_NON_ACCOMPAGNE) {
				reduction = (prixDeBase * 15.0) / 100.0;
			} else if (passager == ProfilPassager.JEUNE) {
				reduction = (prixDeBase * 25.0) / 100.0;
			} else if (passager == ProfilPassager.ETUDIANT) {
				reduction = (prixDeBase * 25.0) / 100.0;
			} else if (passager == ProfilPassager.SENIOR) {
				reduction = (prixDeBase * 30.0) / 100.0;
			}

		}
	}

	/**
	 * Méthode de réduction si le transport associé au billet est un avion ou
	 * autre la réduction dépend du temps du trajet et du type de passager.
	 * 
	 */
	private void bonusReductionAvionAutre() {
		GregorianCalendar date = TempsTrajet();
		boolean memeJour = dateEqual(typeTrajet.getDateArrivee(), (typeTrajet
				.getDateDepart()));
		if (memeJour == true && date.get(Calendar.HOUR) < 3) { // trajet cours
			if (passager == ProfilPassager.ENFANT) {
				reduction = (prixDeBase * 20.0) / 100.0;
			} else if (passager == ProfilPassager.ENFANT_NON_ACCOMPAGNE) {
				reduction = (prixDeBase * 10.0) / 100.0;
			} else if (passager == ProfilPassager.JEUNE) {
				reduction = (prixDeBase * 15.0) / 100.0;
			} else if (passager == ProfilPassager.ETUDIANT) {
				reduction = (prixDeBase * 15.0) / 100.0;
			} else if (passager == ProfilPassager.SENIOR) {
				reduction = (prixDeBase * 20.0) / 100.0;
			}

		} else {// Trajet long
			if (passager == ProfilPassager.ENFANT) {
				reduction = (prixDeBase * 50.0) / 100.0;
			} else if (passager == ProfilPassager.ENFANT_NON_ACCOMPAGNE) {
				reduction = (prixDeBase * 35.0) / 100.0;
			}

		}
	}

	/**
	 * Méthode prixDefinitif calcul le prix définitif dépendant de la réduction
	 * et des options
	 * 
	 * @return prix Définitif
	 */
	public double prixDefinitif() {
		typeReduction();
		double prixFinal = prixDeBase - reduction;
		if (repas == true && carteFidelite == false) { // si le passager à la
														// carte de Fidelite le
														// repas est offert
			double supplement = (prixDeBase * 2.0) / 100.0;
			prixFinal = prixFinal + supplement;

		}
		if (bonusConfort == true && !(typeTrajet.getVehicule() instanceof Bus)) {
			double supplement = (prixDeBase * 15.0) / 100.0;
			prixFinal = prixFinal + supplement;

		}
		if (premiereClasse == true && classeAffaire == false
				&& !(typeTrajet.getVehicule() instanceof Bus)) {
			double supplement = (prixDeBase * 35.0) / 100.0;
			prixFinal = prixFinal + supplement;
		}
		if (classeAffaire == true
				&& premiereClasse == false
				&& (!(typeTrajet.getVehicule() instanceof Bus)
						&& !(typeTrajet.getVehicule() instanceof Bateau) && !(typeTrajet
						.getVehicule() instanceof Train))) {
			double supplement = (prixDeBase * 25.0) / 100.0;
			prixFinal = prixFinal + supplement;
			System.out.println(classeAffaire);
			System.out.println("sup" + supplement);
		}
		if (typeTrajet.getTypeDeBase() != "Modifiable" && modifier == true) {
			double supplement = (prixDeBase * 5.0) / 100.0;
			prixFinal = prixFinal + supplement;

		}
		return prixFinal;
	}

	/**
	 * Formater l'objet pour la sauvegarde
	 * 
	 * @return les informations sur l'objet
	 * 
	 */
	public String print() {
		return this.client.print() + this.typeTrajet.print() + ";"
				+ this.prixDeBase + ";" + this.carteFidelite + ";"
				+ this.bonusConfort + ";" + this.repas + ";"
				+ this.typeDeBillet;
	}

	@Override
	public String toString() {
		String s = "Récapitulatif de votre billet : " + "\n" + "Nom :"
				+ client.getNom() + "  Prénom :" + client.getPrenom() + "\n"
				+ "Départ : "
				+ this.typeTrajet.getDateDepart().get(Calendar.DAY_OF_MONTH)
				+ "/" + this.typeTrajet.getDateDepart().get(Calendar.MONTH)
				+ "/" + this.typeTrajet.getDateDepart().get(Calendar.YEAR)
				+ " à " + this.typeTrajet.getVilleDepart().getNom() + "\n"
				+ "Arrivée : "
				+ this.typeTrajet.getDateArrivee().get(Calendar.DAY_OF_MONTH)
				+ "/" + this.typeTrajet.getDateArrivee().get(Calendar.MONTH)
				+ "/" + this.typeTrajet.getDateArrivee().get(Calendar.YEAR)
				+ " à " + this.typeTrajet.getVilleArrivee().getNom() + "\n"
				+ "Options :";
		if (typeTrajet.getTypeDeBase() != "Modifiable" && modifier == true) {
			s = s + "Modifiable ;";
		} else {
			s = s + this.typeDeBillet + ";";
		}
		if (repas == true) {
			s = s + " Repas ; ";
		}
		if (bonusConfort == true) {
			s = s + " Couchette/Cabine ; ";
		}
		if (carteFidelite == true) {
			s = s + " Carte de Fidelité";
		}
		s = s + "\n" + "Prix Total : " + this.prixDefinitif();
		return s;
	}

	// Mutateur//
	public ProfilPassager getPassager() {
		return passager;
	}

	public void setPassager(ProfilPassager passager) {
		this.passager = passager;
	}

	public Client getClient() {
		return client;
	}

	public void setClient(Client client) {
		this.client = client;
	}

	public Trajet getTypeTrajet() {
		return typeTrajet;
	}

	public void setTypeTrajet(Trajet typeTrajet) {
		this.typeTrajet = typeTrajet;
	}

	public double getPrixDeBase() {
		return prixDeBase;
	}

	public void setPrixDeBase(double prixDeBase) {
		this.prixDeBase = prixDeBase;
	}

	public String getTypeDeBillet() {
		return typeDeBillet;
	}

	public void setTypeDeBillet(String typeDeBillet) {
		this.typeDeBillet = typeDeBillet;
	}

	public double getReduction() {
		return reduction;
	}

	public void setReduction(double reduction) {
		this.reduction = reduction;
	}

	public boolean isPremiereClasse() {
		return premiereClasse;
	}

	public void setPremiereClasse(boolean premiereClasse) {
		this.premiereClasse = premiereClasse;
	}

	public boolean isClasseAffaire() {
		return classeAffaire;
	}

	public void setClasseAffaire(boolean classeAffaire) {
		this.classeAffaire = classeAffaire;
	}

	public boolean isRepas() {
		return repas;
	}

	public void setRepas(boolean repas) {
		this.repas = repas;
	}

	public boolean isBonusConfort() {
		return bonusConfort;
	}

	public void setBonusConfort(boolean bonusConfort) {
		this.bonusConfort = bonusConfort;
	}

	public boolean isCarteFidelite() {
		return carteFidelite;
	}

	public void setCarteFidelite(boolean carteFidelite) {
		this.carteFidelite = carteFidelite;
	}

	public boolean isModifier() {
		return modifier;
	}

	public void setModifier(boolean modifier) {
		this.modifier = modifier;
	}
}
